//
//  BenRefreshableViewModel.swift
//  RefreshScroll
//
//  Created by Ben on 2022/3/3.
//

import SwiftUI
import Combine

enum BenRefreshState {
    case normal
    case pullDown
    case pullUp
    case refreshHeader
    case refreshFooter
}

class BenRefreshableViewModel: ObservableObject {
    
    let progressViewHeight: CGFloat = 50
    var normalOffsetY: CGFloat = 0
    var scrollHeight: CGFloat = 0
    var scrollContentHeight: CGFloat = 0
    
    @Published var refreshFooterCurrHeight: CGFloat = 0
    @Published var showRefreshFooter: Bool = false
    @Published var refreshHeaderCurrHeight: CGFloat = 0
    @Published var currOffsetY: CGFloat = 0
    @Published var state: BenRefreshState = .normal
    
    private var canRefreshPublisher: AnyPublisher<Bool, Never> {
        Publishers.CombineLatest($currOffsetY, $state)
            .map { currOffsetY, state -> Bool in
                if currOffsetY - self.normalOffsetY <= self.progressViewHeight && state == .pullDown {
                    return true
                } else {
                    return false
                }
            }
            .eraseToAnyPublisher()
    }
    
    private var updatePorgressViewHeightPublisher: AnyPublisher<CGFloat, Never> {
        Publishers.CombineLatest($currOffsetY, $state)
            .map { currOffsetY, state -> CGFloat in
                
                var _progressViewHeight: CGFloat = currOffsetY - self.normalOffsetY
                if state == .refreshHeader {
                    if _progressViewHeight < self.progressViewHeight {
                        _progressViewHeight = self.progressViewHeight
                    }
                }
                if _progressViewHeight < 0 {
                    _progressViewHeight = 0
                }
                return _progressViewHeight
            }
            .eraseToAnyPublisher()
    }
    
    private var cancellable: Set<AnyCancellable> = []
    
    
    init() {
        
        canRefreshPublisher
            .dropFirst()
            .removeDuplicates()
            .sink { canRefresh in
                
                if canRefresh {
                    self.state = .refreshHeader
                    
                }
            }
            .store(in: &cancellable)
        
        updatePorgressViewHeightPublisher
            .dropFirst()
            .removeDuplicates()
            .sink { height in
                DispatchQueue.main.async {
                    if self.state == .pullDown {
                        self.refreshHeaderCurrHeight = height
                    } else {
                        withAnimation {
                            self.refreshHeaderCurrHeight = height
                        }
                    }
                }
            }
            .store(in: &cancellable)
    }
   
}

